package com.pansoft.openplanet.fragment;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.appcompat.app.AppCompatDialogFragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import com.efounder.constant.EnvironmentVariable;
import com.efounder.frame.utils.Constants;
import com.efounder.util.EnvSupportManager;
import com.efounder.utils.ResStringUtil;
import com.pansoft.nfc.mifare.Common;
import com.pansoft.nfc.mifare.activity.MifareNfcMessageActivity;
import com.pansoft.openplanet.R;
import com.pansoft.openplanet.account.util.EosAccountGenerator;
import com.pansoft.openplanet.activity.BleBlutoothScanActivity;
import com.pansoft.openplanet.activity.TransactionResultActivity;
import com.pansoft.openplanet.bean.Account;
import com.pansoft.openplanet.bean.AssetListBean;
import com.pansoft.openplanet.blockchain.api.EosChainInfo;
import com.pansoft.openplanet.blockchain.chain.SignedTransaction;
import com.pansoft.openplanet.blockchain.types.TypeChainId;
import com.pansoft.openplanet.constant.IPAssetsConstant;
import com.pansoft.openplanet.db.AccountDao;
import com.pansoft.openplanet.util.BalanceUtil;
import com.pansoft.openplanet.util.BtcNetParamUtil;
import com.pansoft.openplanet.util.BtcTransactionManager;
import com.pansoft.openplanet.util.EosNetParamUtil;
import com.pansoft.openplanet.util.EthTokenTransactionManager;
import com.pansoft.openplanet.util.TCAccountManager;
import com.pansoft.openplanet.util.UTXOTransactionManager;
import com.pansoft.openplanet.widget.PassWordAlertDialog;
import com.pansoft.openplanet.widget.TCLoadingDataView;
import com.utilcode.util.StringUtils;
import com.utilcode.util.ToastUtils;

import org.bitcoinj.core.Coin;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Transaction;
import org.json.JSONObject;
import org.web3j.crypto.Credentials;
import org.web3j.tx.Contract;
import org.web3j.utils.Convert;

import java.math.BigDecimal;
import java.math.BigInteger;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

import static android.app.Activity.RESULT_OK;

/**
 * @author will
 * 弹出的转账确认界面
 */
public class BottomTransferConfirmDialogFragment extends AppCompatDialogFragment implements View.OnClickListener, BtcTransactionManager.OnSyncListener {

    public static final String TAG = "BottomTransferConfirmDialogFragment";
    public static final int REQUEST_READ_NFC_PRIV_KEY = 1895;
    private Context mContext;
    //mode就是chainid
    private int chainId;
    String amount;//金额
    String note; //备注
    String receiveAddress;//收款地址
    String payAddress; //付款地址
    String walletName;//钱包账户名
    private TextView tvWalltName;
    String gas;//转账费用
    String convertGas;//转账费用
    AssetListBean assetListBean;
    int accountType;
    private EthTokenTransactionManager transactionManager;
    private AccountDao accountDao;
    private BtcTransactionManager btcTransactionManager;
    private Disposable disposable;

    public BottomTransferConfirmDialogFragment() {
    }


    @Override
    public void onStart() {
        super.onStart();
        getDialog().getWindow()
                .setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
        getDialog().getWindow().setGravity(Gravity.BOTTOM);
        getDialog().setCanceledOnTouchOutside(true);
        getDialog().setCancelable(true);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(DialogFragment.STYLE_NORMAL, R.style.CustomDialog);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.open_planet_transfer_confirm_pop, container, false);
        initView(rootView);
        accountDao = new AccountDao(mContext);
        return rootView;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (btcTransactionManager != null) {
            btcTransactionManager.removeOnSyncListener(this);
        }
    }

    private void initView(View contentView) {

        tvWalltName = contentView.findViewById(R.id.tv_wallt_name);
        ImageView ivClose;
        TextView tvAmount;
        TextView tvPayInfo;
        TextView tvReceiveAddress;
        TextView tvPayAddress;
        TextView tvMinerFee;
        TextView tvMinerFeeTotal;
        TextView tvGasFormula;
        TextView tvNextt;

        ivClose = (ImageView) contentView.findViewById(R.id.iv_close);
        ivClose.setOnClickListener(this);
        tvAmount = (TextView) contentView.findViewById(R.id.tv_amount);
        tvAmount.setText(amount);
        tvPayInfo = (TextView) contentView.findViewById(R.id.tv_pay_info);
        tvPayInfo.setText(note);
        tvReceiveAddress = (TextView) contentView.findViewById(R.id.tv_receive_address);
        tvReceiveAddress.setText(receiveAddress);
        tvPayAddress = (TextView) contentView.findViewById(R.id.tv_pay_address);
        tvPayAddress.setText(payAddress);
        tvMinerFee = (TextView) contentView.findViewById(R.id.tv_miner_fee);
        tvMinerFeeTotal = (TextView) contentView.findViewById(R.id.tv_miner_fee_total);
        tvMinerFeeTotal.setText(convertGas + " ETH");
        if (chainId == IPAssetsConstant.CHAIN_ID_BTC) {
            tvMinerFeeTotal.setText(convertGas + " BTC");
        }
        if (chainId == IPAssetsConstant.CHAIN_ID_ETE) {
            tvMinerFeeTotal.setText(convertGas + " ETE");
        }
        if (chainId == EosNetParamUtil.getEosChainId()) {
            tvMinerFee.setVisibility(View.GONE);
            tvMinerFeeTotal.setVisibility(View.GONE);
        }
        tvGasFormula = (TextView) contentView.findViewById(R.id.tv_gas_formula);
        tvWalltName.setText(walletName);
        tvNextt = (TextView) contentView.findViewById(R.id.tv_nextt);
        tvNextt.setOnClickListener(this);

    }

    /**
     * 设置数据
     *
     * @param context
     * @param amount         money
     * @param note           备注
     * @param receiveAddress 收款人
     * @param payAddress     付款地址
     * @param walletName     钱包名
     * @param gas            手续费
     * @param convertGas   装换后的手续费只用于显示！
     * @param assetListBean
     */
    public void setData(Context context, int chainId, String amount, String note, String receiveAddress,
                        String payAddress, String walletName, String gas,String convertGas, AssetListBean assetListBean,
                        int accountType) {
        this.chainId = chainId;
        this.amount = amount;
        if (chainId == IPAssetsConstant.CHAIN_ID_EOS) {
            this.amount = amount + " EOS";
        } else if (chainId == IPAssetsConstant.CHAIN_ID_EOSTEST) {
            this.amount = amount + " SYS";
        }
        this.mContext = context;
        this.note = note;
        this.receiveAddress = receiveAddress;
        this.payAddress = payAddress;
        this.walletName = walletName;
        this.gas = gas;
        this.convertGas = convertGas;
        this.assetListBean = assetListBean;
        this.accountType = accountType;
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.iv_close) {
            dismiss();
        } else if (id == R.id.tv_nextt) {

            showPasswordDialog();
        }
    }

    private void beginTransaction() {
        transactionManager = new EthTokenTransactionManager(mContext);
        Account account = accountDao.getAccount(payAddress);
        if (account != null)
            transactionManager.loadCredentialsASync(account,
                    new EthTokenTransactionManager.LoadCredentialsCallBack() {
                        @Override
                        public void loadResult(boolean isSuccess, Credentials credentials) {
                            ethCredentialToTx(isSuccess, credentials);
                        }
                    });
    }

    /**
     * eth转账，获取credential之后的步骤
     * @param isSuccess 是否获取秘钥成功
     * @param credentials 秘钥
     */
    private void ethCredentialToTx(boolean isSuccess, final Credentials credentials) {
        if (!isSuccess) {
            handleETHTransferResult(null, false);
            return;
        }
        //2.获取nonce
//                            LogUtils.i("获取nonce", credentials.getAddress());
        transactionManager.getTransactionNonce(payAddress, chainId, new EthTokenTransactionManager.NonceCallBack() {
            @Override
            public void nonceResult(boolean isSuccess, BigInteger nonce) {
                if (!isSuccess) {
                    handleETHTransferResult(null, false);
                    return;
                }
                //3.开始转账
//                                    LogUtils.i("开始转账", nonce);
                //普通转账
                if (assetListBean == null) {
                    transactionManager.startEthTransaction(nonce, payAddress,
                            EnvironmentVariable.getProperty(Constants.CHAT_USER_ID),
                            receiveAddress, "",
                            Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger(),
                            credentials, chainId + "",
//                            Convert.toWei(gas, Convert.Unit.ETHER).toBigInteger().divide(Contract.GAS_LIMIT),
                            Convert.toWei(gas + "", Convert.Unit.GWEI).toBigInteger(),
                            Contract.GAS_LIMIT, new EthTokenTransactionManager.TransactionCallBack<String>() {
                                @Override
                                public void transactionResult(boolean isSuccess, String result) {
                                    if (!isSuccess) {
                                        handleETHTransferResult(result, false);
                                        return;
                                    }
                                    //转账成功
                                    // TODO: 18-6-14
                                    try {
                                        handleETHTransferResult(result, true);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }

                                }
                            });
                } else {
                    //智能合约转账
                    //矿工费
                    BigInteger gasPrice = Convert.toWei(gas + "", Convert.Unit.GWEI).toBigInteger();

                    transactionManager.startEthTokenTransaction(nonce, payAddress,
                            EnvironmentVariable.getProperty(Constants.CHAT_USER_ID),
                            receiveAddress, "",
//                                                Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger(),
                            new BigDecimal(amount).multiply(BigDecimal.TEN.pow(assetListBean.getTokenDecimals())).toBigInteger(),
                            amount, credentials, gasPrice,
                            assetListBean.getAddress(),
                            Byte.valueOf(assetListBean.getBlockChainID()), assetListBean.getId(),
                            assetListBean.getName(), new EthTokenTransactionManager.TransactionCallBack<String>() {
                                @Override
                                public void transactionResult(boolean isSuccess, String result) {
                                    if (!isSuccess) {
                                        handleETHTransferResult(result, false);
                                        return;
                                    }
                                    //转账成功
                                    handleETHTransferResult(result, true);
                                }
                            });
                }
            }
        });
    }

    /**
     * 使用私钥交易
     * @param privKey 私钥
     */
    private void startEthTxByPrivKey(String privKey) {
        transactionManager = new EthTokenTransactionManager(mContext);
        Account account = accountDao.getAccount(payAddress);
        if (account != null) {
            transactionManager.loadCredentialsByPrvkeyASync(privKey, new EthTokenTransactionManager.LoadCredentialsCallBack() {
                @Override
                public void loadResult(boolean isSuccess, Credentials credentials) {
                    ethCredentialToTx(isSuccess, credentials);
                }
            });
        }
    }

    /**
     * 转账前先同步
     */
    private void beginBTCTx() {
        Account account = accountDao.getAccount(payAddress);
        String filePath = account.getFileName();
        TCLoadingDataView.show(getActivity(), ResStringUtil.getString(R.string.common_text_syncing));
        btcTransactionManager = BtcTransactionManager.getInstance(account.getAddress(), filePath);
        btcTransactionManager.removeOnSyncListener(this);
        btcTransactionManager.addOnSyncListener(this);
        btcTransactionManager.startSync();
    }

    @Override
    public void onSyncProgress(int progress, String currentBtcAddress) {

    }

    @Override
    public void onSyncCompleted(String currentBtcAddress) {
        //同步成功，开始转账
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                TCLoadingDataView.dismiss();
                startBTCTx(btcTransactionManager);
            }
        });
    }

    /**
     * 开始转账
     *
     * @param manager BtcTransactionManager
     */
    private void startBTCTx(BtcTransactionManager manager) {
//        manager.startTransaction("n2ZuNg8nd8EbGpwXWoQzHbf6oVmdv67ntH",
        manager.startTransaction(receiveAddress,
                Coin.valueOf(BalanceUtil.btcToBiInteger(amount).longValue()), Coin.valueOf(10000),
                new BtcTransactionManager.OnTransactionListener() {
                    @Override
                    public void onTxSuccess(Transaction tx) {
                        handleBTCTxResult(tx);
                    }

                    @Override
                    public void onTxFail(String e) {
                        TCLoadingDataView.dismiss();
                        ToastUtils.showShort(e);
                    }
                });
    }

    /**
     * 开始UTXO转账
     * @param pathOrMnemonic 传入路径或者助记词，如果是路径，从本地取出Wallet
     *                       否则是助记词，从助记词获取Wallet
     * @param manager
     */
    private void startUTXOTx(boolean isHdWallet, UTXOTransactionManager manager, String pathOrMnemonic) {
        TCLoadingDataView.show(getActivity(), ResStringUtil.getString(R.string.open_planet_asset_transfer));
        Coin gasCoin = Coin.valueOf(3000);
        if (isHdWallet) {
            // FIXME: 19-11-23
            //这种情况，gas是一个整数，单位sat/byte，为了兼容代码，先这样写
            gasCoin = Coin.valueOf(Long.valueOf(gas));
        }
        manager.getUTXO(getActivity(), TAG, payAddress, pathOrMnemonic, receiveAddress,
                Coin.valueOf(BalanceUtil.btcToBiInteger(amount).longValue()), gasCoin,
                isHdWallet,
                new UTXOTransactionManager.OnTransactionListener() {
                    @Override
                    public void onTxSuccess(Transaction tx) {
                        handleBTCTxResult(tx);
                    }

                    @Override
                    public void onTxFail(String e) {
                        TCLoadingDataView.dismiss();
                        ToastUtils.showShort(e);
                    }
                });
    }

    /**
     * EOS
     * 转账
     */
    private void beginEosTransfer() {
        disposable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                EosAccountGenerator eosAccountGenerator = new EosAccountGenerator(getActivity());
                //获取链上的信息
                EosChainInfo eosChainInfo = eosAccountGenerator.getChainInfo(TAG);
                //组织数据，得到transaction tx
                SignedTransaction tx = eosAccountGenerator.parseTransferData(payAddress,
                        receiveAddress, amount, note, eosChainInfo);
                //对tx签名，返回tx的toString json格式
                String packedTx = eosAccountGenerator.signTransaction(payAddress, tx,
                        new TypeChainId(eosChainInfo.getChain_id()));
                //push transaction, 返回交易id
                String txId = eosAccountGenerator.pushTransaction(TAG, packedTx);
                emitter.onNext(txId);
                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                        TCLoadingDataView.show(getActivity(), ResStringUtil.getString(R.string.open_planet_asset_transfer));
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        TCLoadingDataView.dismiss();
                        if (s != null) {
                            handleEosResult(true, s);
                            dismiss();
                        } else {
                            handleEosResult(false, "");
                            dismiss();
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        TCLoadingDataView.dismiss();
                        handleEosResult(false, "");
                        dismiss();
                    }
                });

    }

    private void handleEosResult(boolean success, String txId) {

        Intent intent = new Intent(mContext, TransactionResultActivity.class);
        intent.putExtra("chainId", EosNetParamUtil.getEosChainId());
        intent.putExtra("money", amount.contains("E") ? amount.replace(" EOS", "")
                : amount.replace(" SYS", ""));
        intent.putExtra("receiveWalletAddress", receiveAddress);
        intent.putExtra("sendWalletAddress", payAddress);
        intent.putExtra("txFee", "");
        intent.putExtra("note", note);
        intent.putExtra("success", success);
        intent.putExtra("tradingID", txId);
        startActivity(intent);
        dismiss();
        getActivity().finish();
    }

    private void handleETHTransferResult(String result, boolean success) {
        TCLoadingDataView.dismiss();

        Intent intent = new Intent(mContext, TransactionResultActivity.class);
        intent.putExtra("chainId", this.chainId);
        intent.putExtra("money", amount);
        intent.putExtra("receiveWalletAddress", receiveAddress);
        intent.putExtra("sendWalletAddress", payAddress);
        intent.putExtra("txFee", convertGas);
        intent.putExtra("note", note);


        if (assetListBean != null) {
            intent.putExtra("moneyUnit", assetListBean.getName());
        }
        intent.putExtra("success", success);
        //放入交易hash
        try {
            JSONObject jsonObject = new JSONObject(result);
            intent.putExtra("tradingID", jsonObject.optString("transactionHash",""));
        } catch (Exception e) {
            e.printStackTrace();
        }


        startActivity(intent);
        dismiss();
        getActivity().finish();
    }

    private void handleBTCTxResult(Transaction tx) {
        NetworkParameters params = BtcNetParamUtil.getBtcNetParams();
        Intent intent = new Intent(mContext, TransactionResultActivity.class);
        intent.putExtra("chainId", IPAssetsConstant.CHAIN_ID_BTC);
        intent.putExtra("money", amount);
//        List<TransactionInput> inputs = tx.getInputs();
//        ArrayList<BtcTxIO> btcInputs = new ArrayList<>();
//        for (TransactionInput input : inputs) {
//            BtcTxIO btcTxIO = new BtcTxIO(input.getOutpoint().getConnectedOutput()
//                    .getScriptPubKey().getToAddress(params).toString(), input.getValue().toFriendlyString());
//            btcInputs.add(btcTxIO);
//        }
//        List<TransactionOutput> outputs = tx.getOutputs();
//        ArrayList<BtcTxIO> btcOutputs = new ArrayList<>();
//        for (TransactionOutput output : outputs) {
//            Script script = output.getScriptPubKey();
//            String address = script.getToAddress(params).toString();
//            BtcTxIO btcTxIO = new BtcTxIO(address, output.getValue().toFriendlyString());
//            btcOutputs.add(btcTxIO);
//        }
//        intent.putExtra("receiveAddress", btcOutputs);
//        intent.putExtra("payAddress", btcInputs);
        intent.putExtra("receiveWalletAddress", receiveAddress);
        intent.putExtra("sendWalletAddress", payAddress);
        // FIXME: 19-11-18 btc刚转账完成，拿不到手续费，鉴于我们写死了，这儿显示默认值
        intent.putExtra("txFee", tx.getFee() == null ? "0.00003" : tx.getFee().toFriendlyString());
        intent.putExtra("note", note);
        intent.putExtra("success", true);
        intent.putExtra("tradingID", tx.getHashAsString());
//        if (!jsonObject.optString("result").equals("success")) {
//            intent.putExtra("success", false);
//        }
        TCLoadingDataView.dismiss();
        startActivity(intent);
        dismiss();
        getActivity().finish();
    }

    private void showPasswordDialog() {
        PassWordAlertDialog dialog = new PassWordAlertDialog(getActivity(), new PassWordAlertDialog.OnEnterClick() {
            @Override
            public void passVerifySuccess(String passWord) {
                if (accountType == 2 && chainId != EosNetParamUtil.getEosChainId()) {
                    //冷钱包，连接蓝牙读卡器
                    //todo eos暂不支持冷钱包
                    Intent intent;
                    //支持直接读写nfc
                    if (!EnvSupportManager.isSupportNfcWallet() && !EnvSupportManager.isSupportForceBleNfc()) {
                        return;
                    }
                    if (!EnvSupportManager.isSupportForceBleNfc() && Common.hasMifareClassicSupport(getActivity())){
                        intent = new Intent(getActivity(), MifareNfcMessageActivity.class);
                    } else {
                        //蓝牙读卡器
                        intent = new Intent(getActivity(), BleBlutoothScanActivity.class);
                        intent.putExtra("bleDeviceType", BleBlutoothScanActivity.BLE_TYPE_NFC);
                    }
                    intent.putExtra("address", payAddress);
                    intent.putExtra("createType", BleBlutoothScanActivity.TYPE_READ_PRIV_KEY);
                    startActivityForResult(intent, REQUEST_READ_NFC_PRIV_KEY);
                    return;
                }
                //开始转账
                TCLoadingDataView.show(mContext, ResStringUtil.getString(R.string.open_planet_asset_transfer));
                if (chainId == IPAssetsConstant.CHAIN_ID_ETH || chainId == IPAssetsConstant.CHAIN_ID_TURBOCHAIN
                || chainId == IPAssetsConstant.CHAIN_ID_ETE) {
                    beginTransaction();
                } else if (chainId == IPAssetsConstant.CHAIN_ID_BTC) {
//                    beginBTCTx();
                    AccountDao accountDao = new AccountDao(mContext);
                    com.pansoft.openplanet.bean.Account account = accountDao.getAccount(payAddress);
                    if (EnvSupportManager.isSupportHDWallet() && !StringUtils.isEmpty(account.getHdBtcCurrentChildAddress())) {
                        startUTXOTx(true, new UTXOTransactionManager(), TCAccountManager
                                .decryptByMainPrivKey(account.getSecretMnemonic()));
                    } else {
                        startUTXOTx(false, new UTXOTransactionManager(), account.getFileName());
                    }
                } else if (chainId == EosNetParamUtil.getEosChainId()) {
                    beginEosTransfer();
                }

            }
        });
        dialog.show();

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_READ_NFC_PRIV_KEY) {
            if (resultCode == RESULT_OK) {
                TCLoadingDataView.show(mContext);
                String privKey = data.getStringExtra("privateKey");
                if (chainId == IPAssetsConstant.CHAIN_ID_ETH  || chainId == IPAssetsConstant.CHAIN_ID_ETE
                        || chainId == IPAssetsConstant.CHAIN_ID_TURBOCHAIN) {
                    startEthTxByPrivKey(privKey);
                } else if (chainId == IPAssetsConstant.CHAIN_ID_BTC) {
                    boolean isHdWallet = EnvSupportManager.isSupportHDWallet() &&
                            !StringUtils.isEmpty(accountDao.getAccount(payAddress).getHdBtcCurrentChildAddress());
                    startUTXOTx(isHdWallet, new UTXOTransactionManager(), privKey);
                } else if (chainId == EosNetParamUtil.getEosChainId()) {
                    //todo
                }

            } else {
                onTxFail();
            }
        }
    }

    private void onTxFail() {
        if (chainId == IPAssetsConstant.CHAIN_ID_ETH|| chainId == IPAssetsConstant.CHAIN_ID_ETE
                || chainId == IPAssetsConstant.CHAIN_ID_TURBOCHAIN) {
            handleETHTransferResult("", false);
        } else if (chainId == IPAssetsConstant.CHAIN_ID_BTC) {
            TCLoadingDataView.dismiss();
            ToastUtils.showShort(R.string.open_planet_transfer_fail);
        } else if (chainId == EosNetParamUtil.getEosChainId()) {
            handleEosResult(false, "");
        }
    }
}
